package com.yc.fedex.model.request.rate;

import com.yc.fedex.model.domain.*;
import com.yc.fedex.model.request.ship.CreateShipmentRequest;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Data
public class RateAndTransitTimesRequest {

    private AccountNumber accountNumber;
    private RateRequestControlParameters rateRequestControlParameters;
    private RequestedShipment requestedShipment;
    private List<String> carrierCodes;

    private RateAndTransitTimesRequest(Steps steps) {
        this.accountNumber = steps.accountNumber;
        this.requestedShipment = steps.requestedShipment;
    }

    public static AccountNumberStep request() {
        return new Steps();
    }

    public interface AccountNumberStep {
        RequestedShipmentStep accountNumberStep(String accountNumber);
    }

    public interface RequestedShipmentStep {
        Build requestedShipmentStep(RequestedShipment requestedShipment);
    }

    public interface Build {
        RateAndTransitTimesRequest build();
    }

    public static class Steps implements AccountNumberStep, RequestedShipmentStep, Build {

        private AccountNumber accountNumber;
        private RequestedShipment requestedShipment;

        public Steps() {
        }

        @Override
        public RequestedShipmentStep accountNumberStep(String accountNumber) {
            this.accountNumber = new AccountNumber(accountNumber);
            return this;
        }

        @Override
        public Build requestedShipmentStep(RequestedShipment requestedShipment) {
            this.requestedShipment = requestedShipment;
            return this;
        }

        @Override
        public RateAndTransitTimesRequest build() {
            return new RateAndTransitTimesRequest(this);
        }
    }

    public static class RequestedShipment extends com.yc.fedex.model.domain.RequestedShipment {

        private RequestedShipment(Steps steps) {
            setShipper(steps.shipper);
            setRecipient(steps.recipient);
            setPickupType(steps.pickupType);
            setRequestedPackageLineItems(steps.requestedPackageLineItems);
            setRateRequestType(steps.rateRequestType);
            setServiceType(steps.serviceType);
            setSoldTo(steps.soldTo);
            setTotalWeight(steps.totalWeight);
            setTotalPackageCount(steps.totalPackageCount);
        }

        public static ShipperStep request() {
            return new Steps();
        }

        public interface ShipperStep {
            RecipientStep shipperStep(Address shipper);
        }

        public interface RecipientStep {
            SoldToStep recipientStep(Address recipient);
        }

        public interface SoldToStep {
            PickupTypeStep soldToStep(String accountNumber);
        }

        public interface PickupTypeStep {
            ServiceTypeStep pickupTypeStep(String pickType);
        }

        public interface ServiceTypeStep {
            TotalWeightStep serviceTypeStep(String serviceType);
        }

        public interface TotalWeightStep {
            TotalPackageCountStep totalWeightStep(Double totalWeight);
        }

        public interface TotalPackageCountStep {
            RequestedPackageLineItemsStep totalPackageCountStep(Integer totalPackageCount);
        }

        public interface RequestedPackageLineItemsStep {
            RateRequestTypeStep addRequestedPackageLineItem(WeightUnits weight);

            RateRequestTypeStep requestedPackageLineItemsStep(List<WeightUnits> weights);

            RateRequestTypeStep packageLineItemsStep(List<RequestedPackageLineItems> requestedPackageLineItems);
        }

        public interface RateRequestTypeStep {
            Build rateRequestTypeStep(List<String> rateRequestType);
        }

        public interface Build {
            RequestedShipment build();
        }


        public static class Steps implements ShipperStep, RecipientStep, SoldToStep, PickupTypeStep, ServiceTypeStep, TotalWeightStep,TotalPackageCountStep, RequestedPackageLineItemsStep, RateRequestTypeStep, Build {

            private Trader shipper;

            private Trader recipient;

            private String pickupType;

            private List<RequestedPackageLineItems> requestedPackageLineItems;

            private List<String> rateRequestType;

            private String serviceType;

            private Trader soldTo;

            private Double totalWeight;

            private Integer totalPackageCount;

            @Override
            public RequestedShipment build() {
                return new RequestedShipment(this);
            }

            @Override
            public RecipientStep shipperStep(Address shipper) {
                this.shipper = Trader.builder().address(shipper).build();
                return this;
            }

            @Override
            public SoldToStep recipientStep(Address recipient) {
                this.recipient = Trader.builder().address(recipient).build();
                return this;
            }

            @Override
            public PickupTypeStep soldToStep(String accountNumber) {
                this.soldTo = Trader.builder().accountNumber(new AccountNumber(accountNumber)).build();
                return this;
            }

            @Override
            public ServiceTypeStep pickupTypeStep(String pickType) {
                this.pickupType = pickType;
                return this;
            }

            @Override
            public TotalWeightStep serviceTypeStep(String serviceType) {
                this.serviceType = serviceType;
                return this;
            }

            @Override
            public TotalPackageCountStep totalWeightStep(Double totalWeight) {
                this.totalWeight = totalWeight;
                return this;

            }

            @Override
            public RequestedPackageLineItemsStep totalPackageCountStep(Integer totalPackageCount) {
                this.totalPackageCount = totalPackageCount;
                return this;
            }

            @Override
            public RateRequestTypeStep addRequestedPackageLineItem(WeightUnits weight) {
                if (this.requestedPackageLineItems == null) {
                    this.requestedPackageLineItems = new ArrayList<>();
                }
                requestedPackageLineItems.add(RequestedPackageLineItems.builder().weight(weight).build());
                return this;
            }

            @Override
            public RateRequestTypeStep requestedPackageLineItemsStep(List<WeightUnits> weights) {
                this.requestedPackageLineItems = weights.stream().map(item -> RequestedPackageLineItems.builder().weight(item).build()).collect(Collectors.toList());
                return this;
            }

            @Override
            public RateRequestTypeStep packageLineItemsStep(List<RequestedPackageLineItems> requestedPackageLineItems) {
                this.requestedPackageLineItems = requestedPackageLineItems;
                return this;
            }

            @Override
            public Build rateRequestTypeStep(List<String> rateRequestType) {
                this.rateRequestType = rateRequestType;
                return this;
            }
        }
    }
}
